package com.im.tcp.handler;

import com.im.common.constant.Constants;
import com.im.tcp.utils.SessionSocketHolder;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

/**
 * 心跳处理器，用于处理客户端连接的空闲状态事件
 */
@Slf4j
public class HeartBeatHandler extends ChannelInboundHandlerAdapter {

    private Long heartBeatTime; // 客户端心跳间隔时间

    public HeartBeatHandler(Long heartBeatTime) {
        this.heartBeatTime = heartBeatTime;
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        // 判断evt是否是IdleStateEvent（用于触发用户事件，包含 读空闲/写空闲/读写空闲 ）
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt; // 强制类型转换
            if (event.state() == IdleState.READER_IDLE) { // 判断读空闲事件
                log.info("读空闲");
            } else if (event.state() == IdleState.WRITER_IDLE) { // 判断写空闲事件
                log.info("进入写空闲");
            } else if (event.state() == IdleState.ALL_IDLE) { // 判断读写空闲事件
                Long lastReadTime = (Long) ctx.channel().attr(AttributeKey.valueOf(Constants.ReadTime)).get(); // 获取上一次读取数据的时间
                long now = System.currentTimeMillis(); // 获取当前时间
                if (lastReadTime != null && now - lastReadTime > heartBeatTime) {
                    // 退后台逻辑，若上一次读取数据的时间与当前时间差值大于心跳间隔时间，则认为客户端已离线，进行相应的处理
                    SessionSocketHolder.offlineUserSession((NioSocketChannel) ctx.channel());
                }
            }
        }
    }
}
